/*
 * Copyright 2007-2008 Brian Cavalier
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.bc.iterate;

import java.util.regex.Pattern;

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;

/**
 * IterateUtil contains additional convenience funtions not in the core
 * Iterate class.
 * @author Brian Cavalier
 */
public class IterateUtil {

	/**
	 * IterateUtil cannot be instantiated
	 */
	private IterateUtil() {
		
	}

	/**
	 * Shortcut to using Iterate.each() with Grep.
	 *
	 * @param i Strings over which to iterate
	 * @param pattern Pattern to grep for
	 * @param c Closure<String> to execute for each match
	 */
	public static void grep(Iterable<String> i, Pattern pattern, Closure<String> c)  {
		Iterate.each(i, Iterate.grep(pattern), c);
	}

	/**
	 * Shortcut to using Iterate.each() with Grep.
	 *
	 * @param i Strings over which to iterate
	 * @param pattern Pattern to grep for
	 * @param c Closure<String> to execute for each match
	 */
	public static void grep(Iterable<String> i, String pattern, Closure<String> c)  {
		Iterate.each(i, Iterate.grep(pattern), c);
	}

	/**
	 * Shortcut to using Iterate.each() with Sed
	 *
	 * @param i Strings over which to iterate
	 * @param pattern Pattern to match
	 * @param replacement String to replace each match with
	 * @param c Closure<String> to execute for each match
	 */
	public static void sed(Iterable<CharSequence> i, Pattern pattern, String replacement, Closure<CharSequence> c) {
		Iterate.each(i, Iterate.chain(Iterate.sed(pattern, replacement), c));
	}

	/**
	 * Shortcut to using Iterate.each() with Sed
	 *
	 * @param i Strings over which to iterate
	 * @param pattern Pattern to match
	 * @param replacement String to replace each match with
	 * @param c Closure<String> to execute for each match
	 */
	public static void sed(Iterable<CharSequence> i, String pattern, String replacement, Closure<CharSequence> c) {
		Iterate.each(i, Iterate.chain(Iterate.sed(pattern, replacement), c));
	}
	
	//
	// Partition splits the Collection into two Collections.  Upon
	// return, Collection matching will contain all matching elements
	// and Collection c will contain all non-matching elements.
	//

	@SuppressWarnings({"SuspiciousMethodCalls"})
    public static <T> void partition(Collection<? extends T> c, Collection<? super T> matching, Test<? super T> t)  {
		for(T item : c) {
			if(t.go(item)) {
				matching.add(item);
				c.remove(item);
			}
		}
	}

	// A more optimized version for Lists using ListIterator
	public static <T> void partition(List<? extends T> c, Collection<? super T> matching, Test<? super T> t)  {
		ListIterator<? extends T> i = c.listIterator();
		while(i.hasNext()) {
			T item = i.next();
			if(t.go(item)) {
				matching.add(item);
				i.remove();
			}
		}
	}
	
	//
	// Partition splits the Collection into two Collections.  Upon
	// return, the returned Collection will contain all matching elements
	// and Collection c will contain all non-matching elements.
	//

	@SuppressWarnings({"SuspiciousMethodCalls"})
    public static <T> Collection<T> partition(Collection<? extends T> c, Test<? super T> t)  {
		ArrayList<T> nc = new ArrayList<T>(c.size());
		for(T item : c) {
			if(t.go(item)) {
				nc.add(item);
				c.remove(item);
			}
		}
		nc.trimToSize();
		return nc;
	}

	public static <T> Collection<T> partition(List<? extends T> c, Test<? super T> t)  {
		ArrayList<T> nc = new ArrayList<T>(c.size());
		ListIterator<? extends T> i = c.listIterator();
		while(i.hasNext()) {
			T item = i.next();
			if(t.go(item)) {
				nc.add(item);
				i.remove();
			}
		}
		nc.trimToSize();
		return nc;
	}
}
